package com.siwei.mes.service.system.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Ordering;
import com.siwei.mes.common.query.PageQuery;
import com.siwei.mes.common.util.DateHelper;
import com.siwei.mes.common.util.JsonUtils;
import com.siwei.mes.entity.dto.SupplierCompanyMaterialsDto;
import com.siwei.mes.entity.dto.SupplierCompanyMaterialsFactoryDto;
import com.siwei.mes.entity.dto.SupplierCompanyMaterialsStatistics;
import com.siwei.mes.entity.experiment.ExperimentDetail;
import com.siwei.mes.entity.experiment.coarseAggregate.CoarseAggregateSfx;
import com.siwei.mes.entity.materials.Materials;
import com.siwei.mes.entity.system.SupplierCompanyMaterials;
import com.siwei.mes.entity.system.Warning;
import com.siwei.mes.enums.MaterialsEnum;
import com.siwei.mes.enums.TestProjectEnum;
import com.siwei.mes.enums.WarningEnum;
import com.siwei.mes.mapper.experiment.ExperimentDetailMapper;
import com.siwei.mes.mapper.experiment.ExperimentMapper;
import com.siwei.mes.mapper.materials.MaterialsMapper;
import com.siwei.mes.mapper.materials.MaterialsSpecConfigMapper;
import com.siwei.mes.mapper.materials.SupplierCompanyMapper;
import com.siwei.mes.mapper.materials.SupplierCompanyMaterialsMapper;
import com.siwei.mes.mapper.system.WarningMapper;
import com.siwei.mes.service.materials.MaterialsService;
import com.siwei.mes.service.system.SupplierCompanyMaterialsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.siwei.mes.common.exception.handler.MessageHandler.assertTrue;

/**
 * 供应商物料表(SupplierCompanyMaterials)表服务实现类
 *
 * @author linzi
 * @since 2024-07-17 23:04:40
 */
@Slf4j
@Service
public class SupplierCompanyMaterialsServiceImpl implements SupplierCompanyMaterialsService {
    @Resource
    private SupplierCompanyMaterialsMapper supplierCompanyMaterialsMapper;
    @Resource
    private SupplierCompanyMapper supplierCompanyMapper;
    @Resource
    private MaterialsSpecConfigMapper materialsSpecConfigMapper;
    @Resource
    private WarningMapper warningMapper;
    @Resource
    private MaterialsMapper materialsMapper;
    @Resource
    private MaterialsService materialsService;
    @Resource
    private ExperimentMapper experimentMapper;
    @Resource
    private ExperimentDetailMapper experimentDetailMapper;
    /**
     * 粗骨料规格对应map
     */
    private static final Map<String, List<String>> SPEC_FILTER_MAP = ImmutableMap.<String, List<String>>builder()
            .put("5～10", ImmutableList.of("16.0mm", "10.0mm", "5.0mm", "2.50mm", "筛底"))
            .put("5～16", ImmutableList.of("20.0mm", "16.0mm", "10.0mm", "5.00mm", "2.50mm", "筛底"))
            .put("5～20", ImmutableList.of("25.0mm", "20.0mm", "10.0mm", "5.00mm", "2.50mm", "筛底"))
            .put("5～25", ImmutableList.of("31.5mm", "25.0mm", "16.0mm", "5.00mm", "2.50mm", "筛底"))
            .put("5～31.5", ImmutableList.of("40.0mm", "31.5mm", "20.0mm", "10.0mm", "5.00mm", "2.50mm", "筛底"))
            .put("5～40", ImmutableList.of("50.0mm", "40.0mm", "20.0mm", "10.0mm", "5.00mm", "筛底"))
            .build();


    @Override
    public Long create(SupplierCompanyMaterials entity) {
        assertTrue(supplierCompanyMapper.selectByPrimaryKey(entity.getSupplierCompanyId()) == null, "该供应商不存在");
        assertTrue(materialsSpecConfigMapper.selectByPrimaryKey(entity.getSpecId()) == null, "该物料及规格配置信息不存在");

        /**根据specId查询pk_materials信息*/
        List<Materials> materials = materialsMapper.selectBySpecId(entity.getSpecId());
        if (materials != null && materials.size() > 0) {
            entity.setMaterialsId(materials.get(0).getId());
        }

        entity.init(true);
        supplierCompanyMaterialsMapper.insertSelective(entity);
        return entity.getId();
    }

    @Override
    public void update(SupplierCompanyMaterials entity) {
        assertTrue(materialsSpecConfigMapper.selectByPrimaryKey(entity.getSpecId()) == null, "该物料及规格配置信息不存在");
        SupplierCompanyMaterials supplierCompanyMaterials = supplierCompanyMaterialsMapper.selectByPrimaryKey(entity.getId());

        /**这里先判断物料是否存在*/
        Materials materials = materialsService.checkIsExist(entity.getMaterialsConfigType(), entity.getMaterialsName(), entity.getMaterialsSpec());
        if (materials != null) {
            entity.setMaterialsId(materials.getId());
            entity.setMaterialsNo(materials.getMaterialNo());
            entity.setMaterialsType(materials.getMaterialType());
        }

        if (supplierCompanyMaterials == null) {
            entity.setSupplierCompanyId(entity.getErpCompanyId());
            entity.setSupplierCompanyName(entity.getSupplierCompanyName());
            entity.init(true);
            supplierCompanyMaterialsMapper.insertSelective(entity);
        } else {
            entity.init(false);
            supplierCompanyMaterialsMapper.updateByPrimaryKeySelective(entity);
        }

        /**物料绑定对应的物料规格配置*/
        if (entity.getMaterialsId() != null && entity.getSpecId() != null) {
            log.info("修改供应商物料，同步修改物料规格设置信息，物料id：【{}】，specId：【{}】", entity.getMaterialsId(), entity.getSpecId());
            materialsService.configSpecId(new Materials().setId(entity.getMaterialsId()).setSpecId(entity.getSpecId()));
        }

        if (supplierCompanyMaterials == null || StringUtils.isBlank(supplierCompanyMaterials.getMaterialsConfigSpec()) && StringUtils.isBlank(entity.getMaterialsConfigSpec())) {
            return;
        }

        /** 如果是粗骨料修改了 并且修改前的材料规格和修改后不一致 需要修改对应试验台账实验 详情json **/
        if (MaterialsEnum.COARSE.getCode().equals(materials.getMaterialType()) && !entity.getMaterialsConfigSpec().equals(supplierCompanyMaterials.getMaterialsConfigSpec())) {
            /** 先查询 物料关联的所有待接收 实验中的试验台账 **/
            List<Long> experimentIdList = experimentMapper.getExperimentIdByMaterialsId(entity.getMaterialsId());
            for (Long experimentId : experimentIdList) {
                List<ExperimentDetail> details = experimentDetailMapper.selectByExperimentId(
                        experimentId, TestProjectEnum.COARSE_AGGREGATE_PARAM_CGL_SFX.getCode());

                if (details.isEmpty()) continue;

                ExperimentDetail detail = details.get(0);
                CoarseAggregateSfx sfx = detail.getObjJson().toJavaObject(CoarseAggregateSfx.class);
                String spec = entity.getMaterialsConfigSpec().replaceAll("\\D*(\\d+～\\d+)\\D*", "$1");

                List<String> requiredOrder = SPEC_FILTER_MAP.getOrDefault(spec, ImmutableList.of());

                // 1. 筛选并保留存在的筛孔直径
                Map<String, CoarseAggregateSfx.SfxInfo> existingMap = sfx.getSfxInfo().stream()
                        .collect(Collectors.toMap(CoarseAggregateSfx.SfxInfo::getSkgjzj, s -> s, (existing, replacement) -> existing));

                // 2. 补全缺失的筛孔直径
                List<CoarseAggregateSfx.SfxInfo> updatedSfxList = new ArrayList<>();
                for (String required : requiredOrder) {
                    if (existingMap.containsKey(required)) {
                        updatedSfxList.add(existingMap.get(required));
                    } else {
                        CoarseAggregateSfx.SfxInfo missingSfx = new CoarseAggregateSfx.SfxInfo();
                        missingSfx.setSkgjzj(required);
                        // 补全其他必要字段（如默认值）
                        // missingSfx.setPassRate(new BigDecimal("100.00"));
                        updatedSfxList.add(missingSfx);
                    }
                }
                // 3. 按 SPEC_FILTER_MAP 的顺序严格排序
                Ordering<CoarseAggregateSfx.SfxInfo> ordering = Ordering.explicit(requiredOrder)
                        .onResultOf(CoarseAggregateSfx.SfxInfo::getSkgjzj);
                List<CoarseAggregateSfx.SfxInfo> sortedList = ordering.sortedCopy(updatedSfxList);
                // 4. 更新并保存
                sfx.setSfxInfo(sortedList);
                detail.setObjJson(JsonUtils.beanToObject(sfx));
                experimentDetailMapper.updateByPrimaryKeySelective(detail);
            }
        }
    }

    @Override
    public void delete(Long id) {
        SupplierCompanyMaterials supplierCompanyMaterials = supplierCompanyMaterialsMapper.selectByPrimaryKey(id);
        assertTrue(supplierCompanyMaterials == null, "供应商物料表信息不存在");
        supplierCompanyMaterialsMapper.deleteByPrimaryKey(id);
    }

    @Override
    public PageInfo<SupplierCompanyMaterials> getPage(PageQuery<SupplierCompanyMaterials, SupplierCompanyMaterials> query) {
        SupplierCompanyMaterials searchParam = query.getParams();
        /**这里查询对应的形式检验预警天数*/
        Warning warning = warningMapper.selectByWarningCode(WarningEnum.FORMAL.getCode());
        if (warning != null) {
            searchParam.setWarningDay(warning.getWarningTime());
        }
        return PageHelper.startPage(query.getPageNum(), query.getPageSize())
                .doSelectPageInfo(() -> supplierCompanyMaterialsMapper.getList(searchParam));
    }

    @Override
    public SupplierCompanyMaterials loadById(Long id) {
        return supplierCompanyMaterialsMapper.loadById(id);
    }

    @Override
    public List<SupplierCompanyMaterials> getAll(SupplierCompanyMaterials entity) {
        return supplierCompanyMaterialsMapper.getList(entity);
    }

    @Override
    public List<SupplierCompanyMaterialsFactoryDto> getFactoryList(Long supplierCompanyId, String materialsName, String materialsSpec) {
        return supplierCompanyMaterialsMapper.getFactoryList(supplierCompanyId, materialsName, materialsSpec);
    }

    @Override
    public List<SupplierCompanyMaterialsFactoryDto> getFactoryListByMaterialsType(Integer materialsType) {
        return supplierCompanyMaterialsMapper.getFactoryListByMaterialsType(materialsType);
    }

    @Override
    public List<String> getMaterialsNameList(Integer materialsType) {
        return supplierCompanyMaterialsMapper.getMaterialsNameList(materialsType);
    }

    @Override
    public List<SupplierCompanyMaterialsDto> getMaterialsSpecList(Integer materialsType, String materialsName) {
        return supplierCompanyMaterialsMapper.getMaterialsSpecList(materialsType, materialsName);
    }

    @Override
    public List<SupplierCompanyMaterialsFactoryDto> getMaterialsFactoryList(Integer materialsType, String materialsName, String materialsSpec) {
        return supplierCompanyMaterialsMapper.getMaterialsFactoryList(materialsType, materialsName, materialsSpec);
    }

    @Override
    public SupplierCompanyMaterials saveOrUpdate(SupplierCompanyMaterials companyMaterials) {
        SupplierCompanyMaterials select = new SupplierCompanyMaterials();
        select.setSupplierCompanyId(companyMaterials.getSupplierCompanyId());
        select.setMaterialsType(companyMaterials.getMaterialsType());
        select.setMaterialsId(companyMaterials.getId());
        select.setSpecId(companyMaterials.getSpecId());
        select.setMaterialsName(companyMaterials.getMaterialsName());
        select.setMaterialsSpec(companyMaterials.getMaterialsSpec());

        SupplierCompanyMaterials isExist = supplierCompanyMaterialsMapper.checkIsExist(select);
        if (isExist == null) {
            companyMaterials.syncInit(true);
            supplierCompanyMaterialsMapper.insertSelective(companyMaterials);
        } else {
            companyMaterials.syncInit(false);
            companyMaterials.setId(isExist.getId());
            supplierCompanyMaterialsMapper.updateByPrimaryKeySelective(companyMaterials);
        }
        return supplierCompanyMaterialsMapper.loadById(companyMaterials.getId());
    }

    @Override
    public SupplierCompanyMaterialsStatistics getStatistics(Long supplierCompanyId) {
        SupplierCompanyMaterialsStatistics statistics = new SupplierCompanyMaterialsStatistics();

        List<SupplierCompanyMaterials> list = supplierCompanyMaterialsMapper.getList(new SupplierCompanyMaterials().setSupplierCompanyId(supplierCompanyId));
        statistics.setMaterialsCount(list.size());
        /***
         * 型检预警：根据配置时间，当配置时间+当前日期大于型式检验到期时间，则预警
         * 型检过期：当前日期大于型式检验到期时间，则过期
         * 复检预警：当前时间-上次复检时间大于配置的复检预警天数
         * 复检过期：当前时间-上次复检时间大于复检有效期
         */
        Integer formalWarnCount = 0;//型检预警个数
        Integer formalOverdueCount = 0;//型检过期个数
        Integer doubleWarnCount = 0;//复检预警个数
        Integer doubleOverdueCount = 0;//复检过期个数

        /**型检相关*/
        Warning formalConfig = warningMapper.selectByWarningCode(WarningEnum.FORMAL.getCode());
        if (formalConfig != null && formalConfig.getWarningTime() != null) {
            int warningTime = formalConfig.getWarningTime();
            for (SupplierCompanyMaterials companyMaterials : list) {
                Date inspectionDateEnd = companyMaterials.getInspectionDateEnd();//型式检验到日时间
                if (inspectionDateEnd == null) {
                    continue;
                }
                /**日期加上预警的时间*/
                Date lastDate = DateHelper.addDate(inspectionDateEnd, Calendar.DATE, warningTime);
                /**型检预警：根据配置时间，当配置时间+当前日期大于型式检验到期时间，则预警*/
                if (lastDate.getTime() > new Date().getTime()) {
                    formalWarnCount++;
                }
                /**型检过期：当前日期大于型式检验到期时间，则过期*/
                if (new Date().getTime() > inspectionDateEnd.getTime()) {
                    formalOverdueCount++;
                }
            }
        }
        /**复检相关*/
        Warning doubleConfig = warningMapper.selectByWarningCode(WarningEnum.DOUBLE.getCode());
        if (doubleConfig != null && doubleConfig.getWarningTime() != null) {
            int warningTime = doubleConfig.getWarningTime();

            for (SupplierCompanyMaterials companyMaterials : list) {
                /**复检预警：当前时间-上次复检时间大于配置的复检预警天数*/
                Date lastExperimentTime = companyMaterials.getLastExperimentTime();//复检时间 是最后一次委托时间
                if (lastExperimentTime == null) {
                    continue;
                }
                long daysBetween = DateHelper.daysBetween(lastExperimentTime, new Date());
                if (daysBetween > warningTime) {
                    doubleWarnCount++;
                }

                /**复检过期：当前时间-上次复检时间大于复检有效期*/
                long between = DateHelper.daysBetween(new Date(), lastExperimentTime);
                if (between > warningTime) {
                    doubleOverdueCount++;
                }
            }

        }
        statistics.setFormalWarnCount(formalWarnCount);
        statistics.setFormalOverdueCount(formalOverdueCount);
        statistics.setDoubleWarnCount(doubleWarnCount);
        statistics.setDoubleOverdueCount(doubleOverdueCount);
        return statistics;
    }
}
